# -*- coding: utf-8 -*-
"""
#-------------------------------------------------------------------------------
# Nom:         traitementDonneesEntree
#
# Auteur:      Alain Gauthier
#
# Créé le:     22/03/2013
# Copyright:   (c) eaucéa 2014
# Licence:     GNU Public Licence (GPL)

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

Construction des chroniques de données pluviométriques pour les
sous bassins versant amont de chaque noeud hydrographique
à partir des bv élémentaires

Ce script doit être lancé depuis l'interface du plugin 'ModelePluieDebit' sous QGIS

#-------------------------------------------------------------------------------
"""

# modules système
import calendar
import os
import glob
import datetime as dt
import shutil
import traceback
import sys
# modules QGIS / GDAL
from qgis.core import *
from qgis.analysis import QgsZonalStatistics
from osgeo import gdal
from osgeo.gdalconst import *
from osgeo.osr import *
import processing
# modules GUI
from PyQt4 import QtCore, QtGui
# modules externes
import numpy as np
# modules internes
import exportCSV
import constantesGeo as cg
import appel_processing


try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    _fromUtf8 = lambda s: s

# constantes désignant le type de chroniques à construire
codePluie = "pluie"
codeEvapo = "evapo"

# constante de nom de fichier log
__fichier_log__= os.path.join(os.getenv('TEMP'),"modelepluiedebit_donnees_entree.log")
# constante du fichier de calcul cumulé sur le pas de temps de calcul
__nom_couche_calcul__="couche_calcul"
# constante du fichier temporaire raster avec maillage fin pour le calcul statistique
__pourcentage_maillage__=1600
__nom_raster_calcul__ = "raster_calcul_fin.tif"

class TraitementDonneesEntree(object):
    """
    Classe implémentant les algorithmes de construction des chroniques invoqués depuis l'interface
    du plugin 'ModelePluieDebit' sous QGIS
    """
    def __ini__(self):
        """
        Constructeur
        """
        self.driver_netCDF = gdal.GetDriverByName('netCDF')
        self.driver_netCDF.Register()
        self.setprogressBar(None)

    #--------------------------------------------------------------------------#

    def setprogressBar(self,AprogressBar):
        """
        gestion de la barre de progression
        """
        self.progressBar = AprogressBar

    #--------------------------------------------------------------------------#

    def ajusterProgressBar(self,Avaleur,Amax):
        """
        ajustement de la jauge en utilisant le rapport Avaleur/Amax
        """
        if Amax==0:
            self.progressBar.setMaximum(0)
            self.progressBar.setValue(0)
        else:
            proportion=100*Avaleur/Amax
            self.progressBar.setValue(proportion)
            QtGui.QApplication.processEvents()

    #--------------------------------------------------------------------------#

    def choixSiDonneesCalculPresentes(self,Achemin):
        """
        Test si Achemin contient des données. Si oui, alors il faut choisir si ces
        données sont conservées
        Renvoie True si les fichiers de calcul doivent être regénérés (avec écrasement éventuel des données), False sinon
        """
        donnees = self.listerDonnees(Achemin,__nom_couche_calcul__+'*')
        resultat = len(donnees)==0
        if not resultat:
            # choix utilisateur sur écrasement des données
            msgBox = QtGui.QMessageBox()
            msgBox.setText(QtGui.QApplication.translate('widgetDonnees',
                                                        u"Le chemin de création des chroniques contient des données."))
            msgBox.setInformativeText(QtGui.QApplication.translate('widgetDonnees',
                                      u"Voulez-vous conserver ces données pour \
                                                le calcul des chroniques (dans le cas contraire elles seront écrasées)?"))
            msgBox.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
            msgBox.setDefaultButton(QtGui.QMessageBox.Yes)
            retour = msgBox.exec_()
            resultat = (retour == QtGui.QMessageBox.No)
            # écrasement des données si réponse = NO
            if resultat:
                for fichier in donnees: os.remove(fichier)
        # renvoie le résultat
        return resultat

    #--------------------------------------------------------------------------#

    def choixSiChroniqueExiste(self,AListe_existe):
        """
        AListe_existe contient les identifiants des noeuds dont les chroniques ont déjà été calculée.
        L'utilisateur doit choisir s'il veut les écraser. S'il veut les conserver,
        il est invité à les déselectionner et recommencer.
        Renvoie True si les chroniques doivent être reconstruites
        """
        resultat = len(AListe_existe)==0
        if not resultat:
            # choix utilisateur sur écrasement des données
            msgBox = QtGui.QMessageBox()
            msgBox.setText(QtGui.QApplication.translate('widgetDonnees',
                                                        u"Les chroniques suivantes existent déjà :"+str(AListe_existe)))
            msgBox.setInformativeText(QtGui.QApplication.translate('widgetDonnees',
                                      u"Voulez-vous les conserver (reprendre alors le calcul en désélectionnant les noeuds à conserver)?"))
            msgBox.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
            msgBox.setDefaultButton(QtGui.QMessageBox.Yes)
            retour = msgBox.exec_()
            # écrasement des données si réponse = NO
            resultat = (retour == QtGui.QMessageBox.No)
        # renvoie le résultat
        return resultat

    #--------------------------------------------------------------------------#

    def coucheParId(self, AIDcouche):
        """
        renvoie la couche ouverte dont l'identifiant est AIDCouche
        """
        return QgsMapLayerRegistry.instance().mapLayer(str(AIDcouche))

    #--------------------------------------------------------------------------#

    def coucheBVTempoSelectionParId(self, AIDcouche):
        """
        renvoie une couche temporaire des éléments sélectionnés à partir de
        la couche ouverte dont l'identifiant est AIDCouche
        """
        # couche depuis l'identifiant AIDcouhe
        couche=QgsMapLayerRegistry.instance().mapLayer(str(AIDcouche))
        proj = couche.dataProvider().crs().authid()
        ensemble_selec = couche.selectedFeaturesIds()
        indice_ident = couche.fieldNameIndex(cg.__ID_ND__)
        # résultat : couche mémoire temporaire
        nomCouche = "couche_memoire"
        coucheResultat = QgsVectorLayer("Polygon?crs="+proj+"&field=" + cg.__ID_ND__ + ":integer&index=yes", nomCouche, "memory")
        # remplissage des données sélectionnées
        for entite in couche.getFeatures():
            if (entite.id() in ensemble_selec):
                coucheResultat.dataProvider().addFeatures([entite])
        # renvoie le résultat
        coucheResultat.commitChanges()
        return coucheResultat



    #--------------------------------------------------------------------------#

    def construireChroniques(self,AIDcoucheBVcalcul,Achemin,Acode):
        """
        Construction de la chronique des données situées dans Achemin pour chaque BV
        de la couche AIDcoucheBVcalcul
        Remarque : seules les entités sélectionnées sont traitées !
        """

        self._fichierlog.write('appel de construireChroniques\r\n')

        # nom du fichier raster de calcul (après reproj+raffinement)
        nomraster_calc = os.path.join(os.getenv('TEMP'),__nom_raster_calcul__)
        # projection raster avant remaillage
        nomraster_reproj = os.path.join(os.getenv('TEMP'),'reproj_'+__nom_raster_calcul__)

        self._fichierlog.write(u'ID couche BV : '+AIDcoucheBVcalcul+u'\r\n')
        self._fichierlog.write(u'raster calcul : '+nomraster_calc+u'\r\n')

        prefixe = 'stat_'
        champ_moyenne = prefixe+'mean'

        # couche contenant les BV de calcul
        coucheBV = self.coucheBVTempoSelectionParId(AIDcoucheBVcalcul)
        self._fichierlog.write('nombre de pts selectionnes : ' + str(coucheBV.pendingFeatureCount())+'\r\n')
        # système de coord de la couche BV
        proj_dst = coucheBV.dataProvider().crs().authid()

        # objet exportant les données vers les fichiers CSV : un fichier par point de calcul
        exporteurCSV = exportCSV.ExportateurChroniqueCSV(coucheBV,Achemin,Acode,cg.__ID_ND__)
        exporteurCSV.declarerFichierLog(self._fichierlog)
        try:
            # champs des fichiers CSV
            exporteurCSV.ouvrirFichiers()
            exporteurCSV.definirChamps(["date",Acode])

            # demande de confirmation si la chronique existe déjà pour chaque fichier
            liste_existe=[]
            dicoFichiers= exporteurCSV.getdicoFichiers()
            for ident in dicoFichiers:
                if os.path.exists(dicoFichiers[ident]):
                    liste_existe.append(ident)
            # confirmation d'écrasement des données
            if not self.choixSiChroniqueExiste(liste_existe):
                return

            # parcours des fichiers de Achemin
            fichiers = self.listerDonnees(Achemin,__nom_couche_calcul__+'*.tif')
            # compteur pour nettoyage des données
            compteur = 0
            nbBv = len(fichiers)
            for fic in fichiers:
                # reprojection nécessaire pour le calcul stat:
                # système de coord de la couche raster chronique
                proj_src = self.coordRasterGDAL(fic)

                # changement de coordonnées
                # sous QGIS 2.2, le script généré directement avec le plugin processing ne fonctionne pas
                # dans un boucle
                appel_processing.reproj_gdal_warp(fic,
                                                  proj_src,
                                                  proj_dst,
                                                  0,
                                                  nomraster_reproj)
                # changement de coordonnées : script généré avec le plugin processing sous QGIS
##                processing.runalg("gdalogr:warpreproject",
##                                  fic,
##                                  proj_src,
##                                  proj_dst,
##                                  0,
##                                  0,
##                                  "",
##                                  nomraster_reproj)
                # construction d'une maille fine
                # raffinement de maillage : "processing" ne fonctionne pas complètement sous QGIS 2.2
                # dans une boucle, le fichier d'entrée est ouvert avec un verrou dès le 1er appel
                # et il est impossible de l'écraser pour le traitement à l'itération suivante
                appel_processing.raffine_gdal_translate(nomraster_reproj,
                                                        __pourcentage_maillage__,
                                                        processing.extent([nomraster_reproj]),
                                                        nomraster_calc)
                # raffinement de maillage : script généré avec le plugin processing sous QGIS
##                processing.runalg("gdalogr:translate",
##                                nomraster_reproj,
##                                __pourcentage_maillage__, # %de pixels en plus par rapport au fichier initial !
##                                True,
##                                "none",
##                                0,
##                                proj_dst,
##                                processing.extent([nomraster_reproj]),
##                                False,
##                                "",
##                                nomraster_calc)
                # calcul des statistiques
                zoneStat = QgsZonalStatistics (coucheBV, nomraster_calc, prefixe, 1)
                zoneStat.calculateStatistics(None)
                # ajout de la statistique trouvée dans les fichiers CSV de chroniques
                ordinal_date = fic.split(__nom_couche_calcul__+'_')[-1].split(os.path.splitext(fic)[-1])[0]
                datedonnee = dt.date.fromordinal(int(ordinal_date))
                # sérialisation
                self._fichierlog.write('serialisation date : ' + datedonnee.isoformat() +'\r\n')
                exporteurCSV.exporterVersCSV(datedonnee.isoformat(),[champ_moyenne])
                # préparation de la couche pour le fichier suivant : suppression des colonnes stat précédentes
                self.supprimerColonnesStat(coucheBV,prefixe)
                # préparation des calculs suivants : suppression des anciens raster
                os.remove(nomraster_calc)
                os.remove(nomraster_reproj)
                # fichier suivant
                compteur=compteur+1
                self.ajusterProgressBar(compteur,nbBv)
                self._fichierlog.flush()
            # fin de boucle sur les fichiers
        finally:
            exporteurCSV.enregistrerTout()

    #--------------------------------------------------------------------------#

    def supprimerColonnesStat(self,AcoucheBV,Aprefixe):
        """
        suppression des colonnes de stat de la couche AcoucheBV
        les colonnes de stat à supprimer sont préfixées par Aprefixe
        """
        champs = AcoucheBV.pendingFields()
        # recherche de Aprefixe en début de champ
        tabIdentASupprimer = []
        for champ in champs:
            nom=unicode(champ.name()).encode("iso-8859-1")
            ident=AcoucheBV.fieldNameIndex(nom)
            if nom.find(Aprefixe)>-1:
                tabIdentASupprimer.append(ident)
        # suppression
        AcoucheBV.dataProvider().deleteAttributes(tabIdentASupprimer)
        # sauvegarde de la modification
        AcoucheBV.commitChanges()

    #--------------------------------------------------------------------------#

    def calculerChroniques(self,AIDcoucheBVcalcul,AcheminDonnees,Adt,Acode):
        """
        lancement du calcul des chroniques sur les BV de la couche AIDcoucheBVcalcul
        à partir des données passées en paramètre dans le chemin AcheminDonnees.
        Si Acode = codePluie alors les données à traiter sont la pluviométrie
        Si Acode = codeEvapo alors les données à traiter sont l'évapotranspiration
        """

        # fichier de log des messages
        self._fichierlog =  open(__fichier_log__,'w')
        try:
            try:
                chemin = QtGui.QFileDialog.getExistingDirectory(None,
                                                                'Choisir le dossier de sortie',
                                                                os.getenv('HOME'),
                                                                QtGui.QFileDialog.ShowDirsOnly)
                if not chemin:
                    return
                # si des fichiers de calcul existent alors il faut demander s'ils doivent être écrasés
                if self.choixSiDonneesCalculPresentes(chemin):
                    # lancement du calcul
                    if Acode==codePluie:
                        self.calculerDonneeDtPluie(AcheminDonnees,Adt,chemin)
                    elif Acode==codeEvapo:
                        self.calculerChroniquesEvapo(AcheminDonnees,Adt,chemin)
                # construction des chroniques
                self.construireChroniques(AIDcoucheBVcalcul,chemin,Acode)
            except Exception, e:
                exc_type, exc_value, exc_traceback = sys.exc_info()
                traceback.print_exc(None,sys.stdout)
                self._fichierlog.write('-'*80+'\n')
                self._fichierlog.write('exception : ' + str(e) +'\n')
                self._fichierlog.write(repr(traceback.extract_tb(exc_traceback)))
                self._fichierlog.write('\n'+'-'*80+'\n')
                self._fichierlog.close()
        finally:
            self._fichierlog.close()
            return chemin

    #--------------------------------------------------------------------------#

    def calculerDonneeDtPluie(self,AcheminDonnees,AdtPluie,AcheminResultat):
        """
        calcul des chroniques de pluie : regroupement des données
        à partir des fichiers contenus dans AcheminDonnees, pour un pas de temps de AdtPluie.
        Le résultat est placé dans AcheminResultat

        HYPOTHESE IMPORTANTE : les fichiers sont chargés par paquet de AdtPluie, ils sont supposés être rangés
        par ordre chronologique !
        """
        self._fichierlog.write('appel de calculerDonneeDtPluie\r\n')
        self._fichierlog.write('chemin des données : ' + AcheminDonnees.encode("utf-8")+'\r\n')
        self._fichierlog.write('chemin des résultats : ' + AcheminResultat.encode("utf-8")+'\r\n')
        self._fichierlog.write('pas de temps : ' + str(AdtPluie)+' jour(s)\r\n')

        # liste des dates des chroniques (au début de chaque intervalle de temps AdtPluie)
        listeDates = []
        # liste de toutes les données d'entrée
        ldonnees = self.listerDonnees(AcheminDonnees,'*.nc')

        if AdtPluie < 28:
            # parcours de données par groupes de pas de temps demandé
            tabDonnees = np.core.empty(AdtPluie,np.object)
        # traitement particulier pour le pas de temps mensuel : la chronique sur les mois calendaires
        else:
            # découpage selon les mois calendaires
            tabDonnees = np.core.empty(31,np.object)

        # initialisations
        indice = 0
        ijour = 0
        mois_traitement=0
        # parcours des fichiers
        compteur=0
        nbMax = len(ldonnees)
        for fic in ldonnees:
            # pas de temps AdtPluie non calendaire
            if AdtPluie < 28:
                # ijour : indice dans le cumul sur AdtPluie
                ijour = indice%AdtPluie
                # fichiers de pluie à cumuler sur AdtPluie
                tabDonnees[ijour] = fic
                # résultat du cumul daté du jour initial sur chaque interval AdtPluie
                if ijour==0:
                    # pour un fichier de précipitation provenant de la série de donnée NASA-TRMM
                    # couche raster des données à un instant donné
                    couche = self.ouvrirRasterGDAL(fic)
                    date_fichier = self.extraireDatePluie(couche.GetMetadataItem('NC_GLOBAL#CoreMetadata.0'),
                                                          'RangeBeginningDate.Value')
                    couche = None
                    # dates des chroniques
                    listeDates.append(date_fichier)
                    self._fichierlog.write('date calcul : ' + str(date_fichier)+'\r\n')
                    self._fichierlog.flush()
                # pluviométrie cumulée au pas de temps AdtPluie
                if (ijour==AdtPluie-1):
                    self.cumulerDonneeAvecDT(tabDonnees,AdtPluie,AcheminResultat,date_fichier)
                indice=indice+1
            # traitement particulier pour le pas de temps mensuel : la chronique sur les mois calendaires
            else:
                # fichiers de pluie à cumuler sur AdtPluie
                tabDonnees[ijour] = fic
                # pour un fichier de précipitation provenant de la série de donnée NASA-TRMM
                # couche raster des données à un instant donné
                couche = self.ouvrirRasterGDAL(fic)
                date_fichier = self.extraireDatePluie(couche.GetMetadataItem('NC_GLOBAL#CoreMetadata.0'),
                                                      'RangeBeginningDate.Value')
                couche = None
                self._fichierlog.write('date calcul : ' + str(date_fichier)+'\r\n')
                self._fichierlog.flush()
                if (ijour==0):
                    # dates des chroniques
                    listeDates.append(date_fichier)
                    # en cours de traitement
                    date_traitement = date_fichier
                if (calendar.monthrange(date_fichier.year,date_fichier.month)[1]==(ijour+1)):
                    # changement de mois : cumul sur le mois précédent (nb de jours : ijour+1)
                    tabDonnees.resize(ijour+1)
                    self._fichierlog.write('longueur tabDonnees : ' + str(len(tabDonnees))+'\r\n')
                    self.cumulerDonneeAvecDT(tabDonnees,ijour,AcheminResultat,date_traitement)
                    # préparation des données pour chgt de mois
                    ijour=0
                    tabDonnees = np.core.empty(31,np.object)
                else:
                    ijour=ijour+1
            compteur+=1
            self.ajusterProgressBar(compteur,nbMax)
        # fin du parcours

    #--------------------------------------------------------------------------#

    def cumulerDonneeAvecDT(self,AtabDonnees,Adt,AcheminResultat,Adate_fichier):
        """
        calcul le cumul de pluie de AtabDonnees sur le pas de temps Adt
        et écriture du résultat dans AcheminResultat
        """
        fichierCalcul=os.path.join(AcheminResultat,__nom_couche_calcul__+'_'+str(Adate_fichier.toordinal()))
        # cumul à calculer
        if Adt>1:
            # les données séparées par des ';'
            liste_donnees=';'.join(AtabDonnees[0:Adt])
            # cumul : script généré avec le plugin processing sous QGIS
            processing.runalg("grass:r.series",
                              liste_donnees,
                              True,
                              10, # opérateur 'sum'
                              "-10000000000,10000000000", # min,max à considérer
                              processing.extent([AtabDonnees[0]]), # étendue de la couche
                              0, # dimension de cellule (0 pour garder celle des couches)
                              fichierCalcul)
        # pas de cumul (toutes les données sont prises)
        else:
            for fichier in AtabDonnees:
                if os.path.exists(fichier):
                    # conversion en fichier tif
                    processing.runalg("grass:r.series",
                                      fichier,
                                      True,
                                      10, # opérateur 'sum'
                                      "-10000000000,10000000000", # min,max à considérer
                                      processing.extent([AtabDonnees[0]]), # étendue de la couche
                                      0, # dimension de cellule (0 pour garder celle des couches)
                                      fichierCalcul)

    #--------------------------------------------------------------------------#

    def extraireDatePluie(self,AmetaDonnees,AnomChamp):
        """
        extraction de la date de la mesure indiquée dans la chaîne Ametadonnees représentant les métadonnées
        des fichiers raster netCDF de la série NASA-TRMM
        """
        # traitement avec un couple champ:valeur par ligne
        liste = AmetaDonnees.splitlines()
        for donnee in liste:
            (champ,sep,valeur) = donnee.partition(':')
            if champ.strip() == AnomChamp:
                valeur = valeur.strip()
                break
        # format yy_mm_dd
        liste_val = valeur.split('/')
        resultat = dt.date(int(liste_val[0]),int(liste_val[1]),int(liste_val[2])) # format yy/mm/dd
        return resultat

    #--------------------------------------------------------------------------#

    def extraireDateEvapo(self,AmetaDonnees):
        """
        extraction de la date de la mesure indiquée dans la chaîne Ametadonnees représentant les métadonnées
        des fichiers raster netCDF de la série NASA-GLDAS
        """
        # format mm_dd_yyyy
        valeur = AmetaDonnees.replace('(00:00)','')
        valeur.strip()
        liste_val = valeur.split('/')
        resultat = dt.date(int(liste_val[2]),int(liste_val[0]),int(liste_val[1])) # format yy/mm/dd
        return resultat

    #--------------------------------------------------------------------------#

    def calculerChroniquesEvapo(self,AcheminDonnees,AdtEvapo,AcheminResultat):
        """
        calcul des chroniques d'évapotranspiration : regroupement des données
        à partir des fichiers contenus dans AcheminDonnees, pour un pas de temps de AdtEvapo.
        Le résultat est placé dans AcheminResultat

        HYPOTHESE IMPORTANTE : les fichiers sont au pas de temps mensuel, ils sont supposés être rangés
        par ordre chronologique !
        """
        self._fichierlog.write('appel de calculerChroniquesEvapo\r\n')
        self._fichierlog.write('chemin des données : ' + AcheminDonnees.encode("utf-8")+'\r\n')
        self._fichierlog.write('chemin des résultats : ' + AcheminResultat.encode("utf-8")+'\r\n')
        self._fichierlog.write('pas de temps : ' + str(AdtEvapo)+' jour(s)\r\n')

        # liste des dates des chroniques (au début de chaque intervalle de temps AdtEvapo)
        listeDates = []
        # liste de toutes les données d'entrée
        ldonnees = self.listerDonnees(AcheminDonnees,'*.nc')

        if AdtEvapo < 28:
            raise ValueError("Seul le traitement de fichiers mensuels est implémenté pour le moment")
        # traitement particulier pour le pas de temps mensuel : la chronique sur les mois calendaires
        else:
            # un fichier par mois (tableau pour compatibilité de traitement)
            tabDonnees = np.core.empty(1,np.object)

        # initialisations
        ijour = 0
        # parcours des fichiers
        compteur=0
        nbMax=len(ldonnees)
        for fic in ldonnees:
            # fichiers d'évapotranspiration
            tabDonnees[ijour] = fic
            # pour un fichier d'évapotranspiration provenant de la série de donnée NASA-GLDAS
            # couche raster des données à un instant donné
            couche = self.ouvrirRasterGDAL(fic)
            item_date=couche.GetMetadataItem('Evap_GDS0_SFC_ave4h#initial_time')
            if item_date==None:
                item_date=couche.GetMetadataItem('Evap_GDS0_SFC#initial_time')
            date_fichier = self.extraireDateEvapo(item_date)
            couche = None
            self._fichierlog.write('date calcul : ' + str(date_fichier)+'\r\n')
            self._fichierlog.flush()
            # dates des chroniques
            listeDates.append(date_fichier)
            # changement de mois
            self.cumulerDonneeAvecDT(tabDonnees,ijour+1,AcheminResultat,date_fichier)
            compteur+=1
            self.ajusterProgressBar(compteur,nbMax)
        # fin du parcours

    #--------------------------------------------------------------------------#

    def ouvrirRaster(self,AnomFichier):
        """
        ouverture du fichier raster AnomFichier
        """

        fileInfo = QtCore.QFileInfo(AnomFichier)
        baseName = fileInfo.baseName()
        rlayer = QgsRasterLayer(AnomFichier, baseName)
        if not rlayer.isValid():
            self._fichierlog.write("Impossible de charger la couche : "+AnomFichier+'\r\n')
        return rlayer

    #--------------------------------------------------------------------------#

    def ouvrirRasterGDAL(self,AnomFichier):
        """
        ouverture du fichier raster AnomFichier
        """
        dataset = gdal.Open(AnomFichier,GA_ReadOnly)
        if dataset is None:
            self._fichierlog.write("Impossible de charger la couche : "+AnomFichier+'\r\n')
        return dataset

    #--------------------------------------------------------------------------#

    def coordRasterGDAL(self,AnomFichier):
        """
        renvoie le système de coordonnées de AnomFichier contenant un raster
        Format de retour : "EPSG:valeur" où valeur est la valeur de référence du système de coordonnées
        """
        # ouverture du raster
        dataset_src = self.ouvrirRasterGDAL(AnomFichier)
        proj = dataset_src.GetProjection()
        systeme_ref_src = SpatialReference(proj)
        # système de coord de la couche raster
        proj_src = "EPSG:"+systeme_ref_src.GetAuthorityCode("GEOGCS")
        # gestion mémoire nécessaire avec GDAL
        proj = None
        systeme_ref_src = None
        dataset_src = None
        # résultat
        return proj_src

    #--------------------------------------------------------------------------#

    def listerDonnees(self,AcheminDonnees,Afiltre):
        """
        renvoie une liste des fichiers du chemin AcheminDonnees satisfaisant le filtre Afiltre
        """
        resultat = glob.glob(os.path.join(AcheminDonnees,Afiltre))
        return resultat

#--------------------------------------------------------------------------#
#--------------------------------------------------------------------------#

if __name__ == '__main__':
    raise EnvironmentError("module devant être exécuté sous console/extension python QGIS")
